﻿#include <QQueue>
#include <QString>
#include <QDebug>
#include <cmath>
#include "kcalculate.h"

//构造函数，注册所有支持的运算符
Calculator::Calculator() {
    registerOperators();
}

//主计算函数：接收表达式字符串，解析并计算后返回最终结果
long double Calculator::calculate(QString& expression) {
    QVector<QString> intermediate;
    strToVector(expression, intermediate); //中缀表达式分词
    if (intermediate.isEmpty()) return 0;

    QQueue<QString> postfix;
    vectorToStack(intermediate, postfix); //转换为后缀表达式

    QStack<long double> result;
    while (!postfix.isEmpty()) {
        QString token = postfix.dequeue();
        bool isNum;
        long double val = token.toDouble(&isNum);
        if (isNum) {
            result.push(val);
        }
        else if (m_unaryOps.contains(token)) {
            m_unaryOps[token](result); //执行一元操作
        }
        else if (m_binaryOps.contains(token)) {
            m_binaryOps[token](result); //执行二元操作
        }
    }
    return result.size() == 1 ? result.top() : NAN;
}

//注册所有支持的一元和二元运算符
void Calculator::registerOperators() {
    m_unaryOps["sqrt"] = [this](QStack<long double>& s) { applySqrt(s); };
    m_unaryOps["^2"] = [this](QStack<long double>& s) { applySquare(s); };
    m_unaryOps["pct"] = [this](QStack<long double>& s) { applyPercent(s); };

    m_binaryOps["+"] = [this](QStack<long double>& s) { applyAdd(s); };
    m_binaryOps["-"] = [this](QStack<long double>& s) { applySub(s); };
    m_binaryOps["*"] = [this](QStack<long double>& s) { applyMul(s); };
    m_binaryOps["/"] = [this](QStack<long double>& s) { applyDiv(s); };
}

//将表达式字符串拆分为 token 序列（支持识别 sqrt、^2、负号），拆分开来
void Calculator::strToVector(const QString& s, QVector<QString>& infix) {
    int n = s.size();
    QString num;
    for (int i = 0; i < n; ++i) {
        //如果是sqrt（，就当做一个独立的 sqrt token，并推进；
        if (i + 4 < n && s.mid(i, 4) == "sqrt" && s[i + 4] == '(') {
            if (!num.isEmpty()) {
                infix.push_back(num);
                num.clear();
            }
            infix.push_back("sqrt");
            i += 3;
            continue;
        }
        QChar c = s[i];
        //跳过空格，不过一般不会有空格，不过以防万一我还是写上了
        if (c.isSpace()) continue;
        if (isNegativePrefix(s, i)) {
            num += c;
        }
        else if (c.isDigit() || c == '.') {
            num += c;
        }
        else {
            //一旦碰到不是数字的字符，就把之前积累的数字加入infix列表。
            if (!num.isEmpty()) {
                infix.push_back(num);
                num.clear();
            }
            if (c == '%') {
                infix.push_back("pct");
            }
            else if (c == '^' && i + 1 < n && s[i + 1] == '2') {
                infix.push_back("^2");
                ++i;
            }
            else {
                infix.push_back(QString(c));
            }
        }
    }
    if (!num.isEmpty()) infix.push_back(num);
}

//中缀表达式转后缀表达式
//3 + 4 × 2 / (1 - 5)^2^3转换为后缀表达式3 4 2 × 1 5 - 2 3 ^ ^ / +
void Calculator::vectorToStack(const QVector<QString>& infix, QQueue<QString>& postfix) {
    QStack<QString> ops;
    for (const QString& token : infix) {
        bool isNum;
        token.toDouble(&isNum);
        if (isNum) {
            postfix.enqueue(token);
        }
        else if (token == "(") {
            ops.push(token);
        }
        else if (token == ")") {
            while (!ops.isEmpty() && ops.top() != "(") {
                postfix.enqueue(ops.pop());
            }
            if (!ops.isEmpty()) ops.pop();
        }
        else {
            int prec = getOperatorPrecedence(token);
            while (!ops.isEmpty() && getOperatorPrecedence(ops.top()) >= prec) {
                postfix.enqueue(ops.pop());
            }
            ops.push(token);
        }
    }
    while (!ops.isEmpty()) postfix.enqueue(ops.pop());
}

//获取运算符的优先级（数值越大优先级越高）
int Calculator::getOperatorPrecedence(const QString& op) {
    if (op == "pct" || op == "^2" || op == "sqrt") return 3;
    if (op == "*" || op == "/") return 2;
    if (op == "+" || op == "-") return 1;
    return 0;
}

//判断当前 - 是前缀负号（非减法）
bool Calculator::isNegativePrefix(const QString& s, int i) {
    if (i < 0 || i >= s.size()) return false;
    QChar c = s[i];
    if (c != '-') return false;
    if (i == 0) return true;
    QChar prev = s[i - 1];
    //判断-的上一个是不是（或者加减乘除这些运算符之一，如果是在数字后面，那就是3-2是减号。如果是运算符后面就是负号
    return prev == '(' || QString("+-*/").contains(prev);
}

//开根号运算 sqrt(x)
void Calculator::applySqrt(QStack<long double>& stack) {
    if (stack.isEmpty()) { stack.push(NAN); return; }
    long double a = stack.pop();
    stack.push(std::sqrt(a));
}

//平方运算 x^2
void Calculator::applySquare(QStack<long double>& stack) {
    if (stack.isEmpty()) { stack.push(NAN); return; }
    long double a = stack.pop();
    stack.push(a * a);
}

//百分比转换 a% -> a/100
void Calculator::applyPercent(QStack<long double>& stack) {
    if (stack.isEmpty()) { stack.push(NAN); return; }
    long double a = stack.pop();
    stack.push(a / 100.0);
}

//加法运算
void Calculator::applyAdd(QStack<long double>& stack) {
    if (stack.size() < 2) { stack.push(NAN); return; }
    long double b = stack.pop();
    long double a = stack.pop();
    stack.push(a + b);
}

//减法运算
void Calculator::applySub(QStack<long double>& stack) {
    if (stack.size() < 2) { stack.push(NAN); return; }
    long double b = stack.pop();
    long double a = stack.pop();
    stack.push(a - b);
}

//乘法运算
void Calculator::applyMul(QStack<long double>& stack) {
    if (stack.size() < 2) { stack.push(NAN); return; }
    long double b = stack.pop();
    long double a = stack.pop();
    stack.push(a * b);
}

//除法运算（b==0时返回NAN）
void Calculator::applyDiv(QStack<long double>& stack) {
    if (stack.size() < 2) { stack.push(NAN); return; }
    long double b = stack.pop();
    if (b == 0) { stack.push(NAN); return; }
    long double a = stack.pop();
    stack.push(a / b);
}
